package cn.xx.service.impl;

import cn.xx.dao.OrderDOMapper;
import cn.xx.dao.SequenceDOMapper;
import cn.xx.dao.StockLogDOMapper;
import cn.xx.dataobject.OrderDO;
import cn.xx.dataobject.SequenceDO;
import cn.xx.dataobject.StockLogDO;
import cn.xx.error.BusinessException;
import cn.xx.error.EmBusinessError;
import cn.xx.service.ItemService;
import cn.xx.service.OrderService;
import cn.xx.service.UserService;
import cn.xx.service.model.ItemModel;
import cn.xx.service.model.OrderModel;
import cn.xx.service.model.UserModel;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author xiexu
 * @create 2022-04-22 16:39
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private ItemService itemService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrderDOMapper orderDOMapper;

    @Autowired
    private SequenceDOMapper sequenceDOMapper;

    @Autowired
    private StockLogDOMapper stockLogDOMapper;

    @Override
    @Transactional
    public OrderModel createOrder(Integer userId, Integer itemId, Integer promoId, Integer amount, String stockLogId) throws BusinessException {
        //1.1校验下单状态，下单的商品是否存在，用户是否合法，购买数量是否正确
        ItemModel itemModel = itemService.getItemByIdInCache(itemId); //根据商品id获取商品信息
        if (itemModel == null) { // 商品是否为空
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "商品信息不存在");
        }

        //1.2校验购买数量
        if (amount <= 0 || amount > 99) { // 购买数量是否小于等于0或者大于等于99
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "数量信息不存在");
        }

        //校验活动信息
//        if (promoId != null) { //因为前端传入的promoId是不可信任的，所以我们在后端业务层要自己校验一次
//            //(1)校验对应活动是否存在这个适用商品
//            if (promoId.intValue() != itemModel.getPromoModel().getId()) {
//                throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "活动信息不正确");
//                //(2)校验活动是否正在进行中
//            } else if (itemModel.getPromoModel().getStatus() != 2) {
//                throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "活动还未开始");
//            }
//        }

        //2.落单减缓存库存（用户下单但还没有付款，锁定库存给当前用户）
        boolean result = itemService.decreaseStock(itemId, amount);
        if (!result) {
            throw new BusinessException(EmBusinessError.STOCK_NOT_ENOUGH);
        }

        //3.订单入库
        OrderModel orderModel = new OrderModel();
        orderModel.setUserId(userId); //订单设置购买用户id
        orderModel.setItemId(itemId); //订单设置商品id
        orderModel.setAmount(amount); //订单设置购买商品的数量
        if (promoId != null) { //如果秒杀活动正在进行则取秒杀价格
            orderModel.setItemPrice(itemModel.getPromoModel().getPromoItemPrice());
        } else { //否则取平常商品价格
            orderModel.setItemPrice(itemModel.getPrice());
        }
        orderModel.setPromoId(promoId);
        // 订单总金额 = 商品单价 * 商品数量
        orderModel.setOrderPrice(orderModel.getItemPrice().multiply(new BigDecimal(amount)));
        // 生成交易流水号(订单号)
        orderModel.setId(generateOrderNo());

        OrderDO orderDO = convertFromOrderModel(orderModel);
        orderDOMapper.insertSelective(orderDO);

        // 商品信息对应的销量需要加上购买的数量
        itemService.increaseSales(itemId, amount);

        // 设置库存流水状态为成功
        StockLogDO stockLogDO = stockLogDOMapper.selectByPrimaryKey(stockLogId);
        if (stockLogDO == null) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR);
        }
        stockLogDO.setStatus(2); //2表示下单扣减库存成功
        stockLogDOMapper.updateByPrimaryKeySelective(stockLogDO);

        //4.返回前端
        return orderModel;
    }

    // 加入REQUIRES_NEW表示不管外部的事务有没有错误，只要我这个方法运行结束了且没有出错就自动提交事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    //不管该方法是否在事务中，都会开启一个新的事务，不管外部事务是否成功
    //最终都会提交掉该事务，为了保证订单号的唯一性，防止下单失败后订单号的回滚
    public String generateOrderNo() {
        //订单有16位
        StringBuilder stringBuilder = new StringBuilder();
        //前8位为时间信息，年月日
        LocalDateTime now = LocalDateTime.now();
        //时间戳格式为20220422
        String nowDate = now.format(DateTimeFormatter.ISO_DATE).replace("-", "");
        stringBuilder.append(nowDate);

        //中间6位为自增序列
        //获取当前sequence
        int sequence = 0;
        SequenceDO sequenceDO = sequenceDOMapper.getSequenceByName("order_info");

        sequence = sequenceDO.getCurrentValue();
        //设置回去当前的(sequence+步长)到数据库，下次拿出来就是增加后的数据了
        sequenceDO.setCurrentValue(sequenceDO.getCurrentValue() + sequenceDO.getStep());
        //更新增加步长后的数据
        sequenceDOMapper.updateByPrimaryKeySelective(sequenceDO);
        //拼接
        String sequenceStr = String.valueOf(sequence);
        //不足6位就往前面添加0
        for (int i = 0; i < 6 - sequenceStr.length(); i++) {
            stringBuilder.append(0);
        }
        stringBuilder.append(sequenceStr);

        //最后两位为分库分表位，暂时不考虑，写死
        stringBuilder.append("00");

        return stringBuilder.toString();
    }

    private OrderDO convertFromOrderModel(OrderModel orderModel) {
        if (orderModel == null) {
            return null;
        }
        OrderDO orderDO = new OrderDO();
        BeanUtils.copyProperties(orderModel, orderDO);
        return orderDO;
    }

}
